/**
 * @file    drv_adc.c
 * @author  yhy
 * @brief   芯必达IM94x系列芯片, adc抽象层
 * @version 1.02
 * @date    2025-07-13
 *
 * @copyright Copyright (c) 2025
 *
 * @details
 * Change Logs:
 * Date           Author       Notes
 * 2025-07-13     yhy          the first version V1.00
 * 2025-07-16     yhy          snf_adc_config_t结构体channel_list参数从指针改为数组 V1.01
 * 2025-08-08     yhy          ADC采样周期变为240，太快会一直进入DMA中断导致中断嵌套 V1.02

 *
 */
#include "drv_adc.h"

#include "adc_drv.h"
#include "dma_drv.h"
#include "drv_gpio.h"
#include "gpio_drv.h"

/**
 * @brief ADC引脚路由
 *
 */
typedef struct
{
    GPIO_Type     *port; /*!< 端口 */
    uint32_t       pin;  /*!< 引脚 */
    gpio_pin_mux_t mux;  /*!< 复用功能 */
} snf_adc_pin_route_t;

/**
 * @brief ADC硬件实例管理
 *
 */
typedef struct
{
    bool           initialized; /*!< 是否已经初始化 */
    uint32_t       hw_instance; /*!< 硬件实例 */
    adc_callback_f callback;    /*!< 回调函数 */
    void          *param;       /*!< 回调函数参数 */
    ADC_Type      *adcX_addr;   /*!< ADC 实例地址 */
} snf_adc_hw_manager_t;

static result_e snf_drv_adc_config(const snf_adc_config_t *adc_config);
static result_e snf_drv_adc_gpio_config(const snf_adc_config_t *adc_config);
static result_e snf_drv_adc_dma_config(const snf_adc_config_t *adc_config);
static void     snf_drv_adc_callback(uint8_t channel, dma_event_t event, void *param);
static result_e snf_drv_adc_param_verify(const snf_adc_config_t *adc_config);

/* ADC 引脚路由表 */
static const snf_adc_pin_route_t adc_pin_route_table[ADC_INSTANCE_MAX][ADC_CHANNEL_MAX] = {
    [ADC_INSTANCE_ADC0] = {
        [ADC_CHANNEL_0] = {.port = GPIOA, .pin = 0, .mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_1] = {.port = GPIOA, .pin = 1, .mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_2] = {.port = GPIOC,.pin = 2,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_3] = {.port = GPIOC,.pin = 3,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_4] = {.port = GPIOB,.pin = 0,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_5] = {.port = GPIOB,.pin = 1,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_6] = {.port = GPIOB,.pin = 2,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_7] = {.port = GPIOB,.pin = 3,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_8] = {.port = GPIOA,.pin = 7,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_9] = {.port = GPIOC,.pin = 8,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_10] = {.port = GPIOC,.pin = 6,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_11] = {.port = GPIOC,.pin = 7,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_12] = {.port = GPIOC,.pin = 14,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_13] = {.port = GPIOC,.pin = 15,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_14] = {.port = GPIOC,.pin = 16,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_15] = {.port = GPIOC,.pin = 1,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_16] = {.port = GPIOC,.pin = 0,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_17] = {.port = GPIOC,.pin = 17,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_18] = {.port = GPIOE,.pin = 2,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_19] = {.port = GPIOE,.pin = 6,.mux = GPIO_PIN_MUX_DISABLED},
    },
    [ADC_INSTANCE_ADC1] = {
        [ADC_CHANNEL_6] = {.port = GPIOA,.pin = 2,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_7] = {.port = GPIOA,.pin = 3,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_8] = {.port = GPIOD,.pin = 2,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_9] = {.port = GPIOD,.pin = 4,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_10] = {.port = GPIOB,.pin = 12,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_11] = {.port = GPIOB,.pin = 13,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_15] = {.port = GPIOE,.pin = 7,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_16] = {.port = GPIOA,.pin = 6,.mux = GPIO_PIN_MUX_DISABLED},
        [ADC_CHANNEL_17] = {.port = GPIOC,.pin = 9,.mux = GPIO_PIN_MUX_DISABLED},
    }
};

/* ADC硬件实例管理列表 */
static snf_adc_hw_manager_t adc_hw_manager_list[ADC_INSTANCE_MAX];

/* ADC硬件实例地址 */
static ADC_Type *adc_hw_addr_table[ADC_INSTANCE_MAX] = { ADC0, ADC1 };

/**
 * @brief 初始化ADC, 注意，一次只能初始化同一个ADC实例的通道
 *
 * @param   adc_config    ADC配置结构体指针
 * @return  result_e      初始化结果, 初始化成功返回RESULT_STATUS_OK, 否则返回错误码
 */
result_e snf_drv_adc_init(const snf_adc_config_t *adc_config)
{
    result_e result = snf_drv_adc_param_verify(adc_config);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    result = snf_drv_adc_gpio_config(adc_config);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    result = snf_drv_adc_config(adc_config);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    result = snf_drv_adc_dma_config(adc_config);
    if (result != RESULT_STATUS_OK) {
        return result;
    }

    adc_hw_manager_list[adc_config->instance].callback    = adc_config->callback;
    adc_hw_manager_list[adc_config->instance].param       = adc_config->param;
    adc_hw_manager_list[adc_config->instance].adcX_addr   = adc_hw_addr_table[adc_config->instance];
    adc_hw_manager_list[adc_config->instance].hw_instance = adc_config->instance;
    adc_hw_manager_list[adc_config->instance].initialized = true;

    ADC_SetNormalChSoftwareTrigger(adc_config->instance);

    return RESULT_STATUS_OK;
}

/**
 * @brief 校验adc配置参数
 *
 * @param adc_config    adc配置结构体指针
 * @return result_e     校验结果, 校验成功返回RESULT_STATUS_OK, 否则返回错误码
 */
static result_e snf_drv_adc_param_verify(const snf_adc_config_t *adc_config)
{
    if (!adc_config) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    if (adc_config->instance >= ADC_INSTANCE_MAX) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    if (adc_config->channel_size > ADC_CHANNEL_MAX) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    for (uint8_t i = 0; i < adc_config->channel_size; ++i) {
        if (adc_config->channel_list[i] >= ADC_CHANNEL_MAX) {
            return RESULT_STATUS_INVALID_PARAM;
        }
    }

    if (adc_config->mode > ADC_MODE_CONTINUE) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    if (adc_config->dma_channel >= ADC_DMA_CHANNEL_MAX) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    if (!adc_config->adc_sample_buf) {
        return RESULT_STATUS_INVALID_PARAM;
    }

    return RESULT_STATUS_OK;
}

/**
 * @brief ADC DMA配置
 *
 * @param adc_config        ADC配置结构体指针
 * @return result_e         DMA配置结果, 配置成功返回RESULT_STATUS_OK, 否则返回错误码
 */
static result_e snf_drv_adc_dma_config(const snf_adc_config_t *adc_config)
{

    dma_perial_request_t dma_perial_request =
        adc_config->instance == ADC_INSTANCE_ADC0 ? DMA_REQ_ADC0 : DMA_REQ_ADC1;

    dma_channel_config_t dma_channel_config = {
        .channel              = adc_config->dma_channel,
        .srcAddress           = 0U,
        .destAddress          = 0U,
        .srcAddressIncrement  = true,
        .destAddressIncrement = true,
        .srcTransferWidth     = DMA_TRANSFER_WIDTH_32BIT,
        .destTransferWidth    = DMA_TRANSFER_WIDTH_32BIT,
        .transferSize         = adc_config->channel_size,
        .transferType         = DMA_TRANSFER_PERIPH2MEM,
        .srcPeriphRequest     = dma_perial_request,
        .destPeriphRequest    = DMA_REQ_DISABLE,
        .circularModel        = true,
        .completeIntEnable    = true,
        .errorIntEnable       = true,
        .callback             = NULL,
        .callbackParam        = NULL,
    };
    dma_channel_config.destAddress = (uint32_t)(adc_config->adc_sample_buf);

    if (adc_config->instance == ADC_INSTANCE_ADC0) {
        dma_channel_config.srcAddress = (uint32_t)(&ADC0->NDR[0]);
    }
    else {
        dma_channel_config.srcAddress = (uint32_t)(&ADC1->NDR[0]);
    }

    DMA_ChannelInit(&dma_channel_config);
    DMA_InstallCallback(adc_config->dma_channel, snf_drv_adc_callback,
                        &(adc_hw_manager_list[adc_config->instance]));
    DMA_StartChannel(adc_config->dma_channel);

    return RESULT_STATUS_OK;
}

/**
 * @brief ADC引脚配置
 *
 * @param   adc_config    ADC配置结构体指针
 * @return  result_e      配置状态, 配置成功返回RESULT_STATUS_OK, 否则返回错误码
 */
static result_e snf_drv_adc_gpio_config(const snf_adc_config_t *adc_config)
{
    for (uint8_t i = 0; i < adc_config->channel_size; ++i) {
        GPIO_Type     *port = adc_pin_route_table[adc_config->instance][adc_config->channel_list[i]].port;
        uint32_t       pin  = adc_pin_route_table[adc_config->instance][adc_config->channel_list[i]].pin;
        gpio_pin_mux_t mux  = adc_pin_route_table[adc_config->instance][adc_config->channel_list[i]].mux;
        GPIO_SetPinFunc(port, pin, mux);
    }

    return RESULT_STATUS_OK;
}

/**
 * @brief 配置ADC, 并调用ADC_Init()
 *
 * @param adc_config    ADC配置结构体指针
 * @return result_e     配置结果, 配置成功返回RESULT_STATUS_OK, 否则返回错误码
 */
static result_e snf_drv_adc_config(const snf_adc_config_t *adc_config)
{
    adc_normal_ch_config_t adc_normal_ch_config[adc_config->channel_size];
    for (uint8_t i = 0; i < adc_config->channel_size; ++i) {
        adc_normal_ch_config[i].channel    = (adc_input_channel_t)(adc_config->channel_list[i]);
        adc_normal_ch_config[i].sampleTime = ADC_SAMPLE_240_CYCLES;
        adc_normal_ch_config[i].neocIntEn  = false;
        adc_normal_ch_config[i].awdIntEn   = false;
        adc_normal_ch_config[i].awdTrigEn  = false;
        adc_normal_ch_config[i].awdEn      = false;
        adc_normal_ch_config[i].awdSel     = ADC_ANALOG_WATCHDOG0;
    }

    adc_normal_sequence_config_t adc_normal_sequence_config = {
        .triggerType = ADC_SOFTWARE_TRIGGER,
        .mode        = (adc_conversion_mode_t)(adc_config->mode),
        .neosIntEn   = false,
        .sequenceLen = adc_config->channel_size - 1,
        .chConfig    = adc_normal_ch_config,
    };

    adc_conversion_config_t adc_conversion_config = {
        .adcEn          = true,
        .intEn          = false,
        .resolution     = ADC_RESOLUTION_12BIT,
        .averageTimes   = ADC_AVERAGE_4,
        .averageEn      = false,
        .dmaMode        = ADC_NORMAL_CHANNEL_DMA_ENABLE,
        .vrefpSel       = ADC_VDDA,
        .normalSequence = &adc_normal_sequence_config,
        .srcClk         = ADC_CLK_SRC_PERI1, /* 24MHz */
        .callback       = NULL,
    };

    ADC_Init(adc_config->instance, &adc_conversion_config);
    return RESULT_STATUS_OK;
}

/**
 * @brief ADC转换完成的回调函数
 *
 * @param channel   转换完成的通道
 * @param event     DMA事件
 * @param prarm     参数
 */
static void snf_drv_adc_callback(uint8_t channel, dma_event_t event, void *param)
{
    snf_adc_hw_manager_t *adc_hw_manager = (snf_adc_hw_manager_t *)param;

    if (!adc_hw_manager->initialized) {
        return;
    }

    switch (event) {
    case DMA_EVENT_TRANFER_COMPLETE:
        if (adc_hw_manager->callback) {
            adc_hw_manager->callback(channel, adc_hw_manager->param);
        }
        break;
    }
}
